#include <iostream>
#include "2dmap.h"
#include "XmlReader.h"
#include <SDL2/SDL.h>

using namespace std;

extern SDL_Keycode keyPressed;

TwoDMap::TwoDMap()
{
    tileWidth = 32;
    tileHeight = 32;
    tileRows = 30;
    tileColumns = 30;
    defaultTile = 31;
    mapSize = Vector2(0, 0);
    mapCoordsToDraw = RectangleWH(0, 0, 10, 10);
    pSpriteSheet = Image::Load("Resources/Images/tile.png");
    screenDrawArea = RectangleWH(0, 0, 0, 0);
    pFloor = new Sprite(pSpriteSheet, Vector2(tileColumns, tileRows), Vector2(tileWidth, tileHeight), 30);

    PopulateMap();


}

TwoDMap::~TwoDMap()
{

}

void TwoDMap::Update(int Delta)
{
    switch (keyPressed)
    {
    case SDLK_LEFT:
        mapCoordsToDraw.SetX(mapCoordsToDraw.GetX() - 1);
        keyPressed = NULL;
        break;
    case SDLK_RIGHT:
        mapCoordsToDraw.SetX(mapCoordsToDraw.GetX() + 1);
        keyPressed = NULL;
        break;
    case SDLK_UP:
        mapCoordsToDraw.SetY(mapCoordsToDraw.GetY() - 1);
        keyPressed = NULL;
        break;
    case SDLK_DOWN:
        mapCoordsToDraw.SetY(mapCoordsToDraw.GetY() + 1);
        keyPressed = NULL;
        break;
    }

//    cout << "pre-check x = " << mapCoordsToDraw.GetX() << " ";
//    cout << "pre-check y = " << mapCoordsToDraw.GetY() << " ";

    // Make sure the map area being drawn is valid
    if (mapCoordsToDraw.GetX() < 0)
    {
            mapCoordsToDraw.SetX(0);
    }
    if (mapCoordsToDraw.GetY() < 0)
    {
            mapCoordsToDraw.SetY(0);
    }
    if (mapCoordsToDraw.GetX() + mapCoordsToDraw.GetWidth() >= mapSize.GetX())
    {
       mapCoordsToDraw.SetX(mapSize.GetX() - int(mapCoordsToDraw.GetWidth()) - 1);
    }
    if (mapCoordsToDraw.GetY() + mapCoordsToDraw.GetHeight() >= mapSize.GetY())
    {
       mapCoordsToDraw.SetY(mapSize.GetY() - int(mapCoordsToDraw.GetHeight()) - 1);
    }
//    cout << "post-check x = " << mapCoordsToDraw.GetX() << " ";
//    cout << "post-check y = " << mapCoordsToDraw.GetY() << endl;

}

void TwoDMap::Draw()
{
    Vector2 coordsOffset = Vector2(mapCoordsToDraw.GetX(), mapCoordsToDraw.GetY()); // x and y are tile coords within the draw window
    for (int y = 0; y < mapCoordsToDraw.GetWidth(); y++)
    {
        for (int x = 0; x < mapCoordsToDraw.GetWidth(); x++)
        {
            if (LocationIsOnMap(PositionOnFullMap(Vector2(x, y),coordsOffset)))
            {
                int spriteNumber = mapData[CoordsToIndex(PositionOnFullMap(Vector2(x, y), coordsOffset))];

                Sprite tileToDraw = Sprite(pSpriteSheet, // Image
                                           Vector2(tileColumns, tileRows), // sprite layout info
                                           Vector2(32, 32), // sprite size
                                           spriteNumber);// sprite number
                Vector2 absoluteDrawPosition = DrawAreaPositionOfTile(Vector2(x, y))
                                                        + Vector2(screenDrawArea.GetX(), screenDrawArea.GetY());
                tileToDraw.Draw(absoluteDrawPosition);
            }
        }
    }

}

//Vector2 TwoDMap::TileScreenPosition(Vector2 tilePosition)
//{
//    return Vector2(tilePosition.GetX() * tileWidth, tilePosition.GetY() * tileHeight);
//}

void TwoDMap::PopulateMap()
{

    XmlReader mapReader("Resources/Maps/untitled.tmx");

    mapReader.StartElement("map");

//    cout << "Map version is " << mapReader.ReadTextAttribute("version") << endl;
//    mapReader.StartElement("tileset");
//    cout << "Tileset first GID is " << mapReader.ReadTextAttribute("firstgid") << endl;
//    mapReader.StartElement("image");
//    cout << "Image source is  " << mapReader.ReadTextAttribute("source") << endl;
//    mapReader.EndElement();
//    mapReader.EndElement();

    mapReader.StartElement("layer");
    mapSize.SetX(mapReader.ReadIntAttribute("width"));
    mapSize.SetY(mapReader.ReadIntAttribute("height"));
    mapReader.StartElement("data");

    mapReader.StartList("tile");

    bool printedFirst = false;
    int counter = 0;


    while (mapReader.MoveToNextListItem())
    {
        int gid = mapReader.ReadIntAttribute("gid");
        //cout << counter << " tile GID is  " << gid << endl;
        mapData.push_back(gid);
        counter++;
    }

    mapReader.EndElement();
    mapReader.EndElement();

    mapReader.EndElement();
}

int TwoDMap::CoordsToIndex(Vector2 coords)
{
    int blah = coords.GetX() + (coords.GetY()  * mapSize.GetX());
     return coords.GetX() + (coords.GetY()  * mapSize.GetX());
}

Vector2 TwoDMap::PositionOnFullMap(Vector2 coords, Vector2 offset)
{

    return coords + offset;
}

bool TwoDMap::LocationIsOnMap(Vector2 coords)
{
    if (coords.GetX() >= 0 && coords.GetX() < mapSize.GetX() &&
        coords.GetY() >= 0 && coords.GetY() < mapSize.GetY())
    {
        return true;
    }
    else
    {
        return false;
    }
}

RectangleWH TwoDMap::DrawAreaInTiles()
{
    RectangleWH drawAreainTiles = RectangleWH(0, 0, 0, 0);
    drawAreainTiles.SetX(mapCoordsToDraw.GetX());
    drawAreainTiles.SetY(mapCoordsToDraw.GetY());
    drawAreainTiles.SetWidth(screenDrawArea.GetWidth() / tileWidth);
    drawAreainTiles.SetHeight(screenDrawArea.GetHeight() / tileHeight);
}

void TwoDMap::SetScreenDrawArea(RectangleWH newArea)
{
    screenDrawArea = newArea;
    mapCoordsToDraw.SetWidth(screenDrawArea.GetWidth() / tileWidth);
    mapCoordsToDraw.SetHeight(screenDrawArea.GetHeight() / tileHeight);
}

RectangleWH TwoDMap::GetScreenDrawArea()
{
    return screenDrawArea;
}

Vector2 TwoDMap::DrawAreaPositionOfTile(Vector2 tileCoords)
{
    Vector2 pixelPosition = Vector2(tileCoords.GetX() * tileWidth,
                                    tileCoords.GetY() * tileHeight);
    return pixelPosition;
}

Vector2 TwoDMap::DrawAreaPositionOfTileInTiles(Vector2 tileCoords)
{
    Vector2 tilePosition = tileCoords + Vector2(Vector2(mapCoordsToDraw.GetX(), mapCoordsToDraw.GetY()));
    return tilePosition;
}
